package com.gitee.ywj1352.dubbo.resilience4j.strategy;

import com.gitee.ywj1352.dubbo.resilience4j.config.BulkheadFactory;
import com.gitee.ywj1352.dubbo.resilience4j.fallback.Fallback;
import io.github.resilience4j.bulkhead.ThreadPoolBulkhead;
import io.vavr.control.Try;
import org.apache.dubbo.common.extension.ExtensionLoader;
import org.apache.dubbo.common.extension.SPI;
import org.apache.dubbo.rpc.*;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@SPI("threadPoolBulkheadTryStrategy")
public class ThreadPoolBulkheadTryStrategy implements TryStrategy {
    @Override
    public Try<Result> getResult(Invoker<?> invoker, Invocation invocation) {
        ThreadPoolBulkhead bulkhead = BulkheadFactory.getSingleton().getThreadPoolBulkheadFactory(invoker, invocation.getMethodName());
        Supplier<CompletionStage<Result>> decoratedSupplier = ThreadPoolBulkhead.decorateSupplier(bulkhead, () -> invoker.invoke(invocation));
        return Try.ofSupplier(decoratedSupplier).map(sr -> {
            try {
                return sr.toCompletableFuture().get(invoker.getUrl().getParameter("timeout", 10L), TimeUnit.MILLISECONDS);
            } catch (Exception e) {
                throw new RuntimeException("");
            }
        }).recover(throwable -> {
            ExtensionLoader<Fallback> extensionLoader = ExtensionLoader.getExtensionLoader(Fallback.class);
            String fallback = invoker.getUrl().getMethodParameter(invocation.getMethodName(), "fallBack");
            Fallback extension = extensionLoader.getExtension(fallback);
            AsyncRpcResult asyncRpcResult = new AsyncRpcResult(CompletableFuture.completedFuture(new AppResponse(extension.doFallback(invocation.getArguments()))), invocation);
            return asyncRpcResult;
        });
    }
}
